package shared

import (
	sqlc "bgs/db/sqlc"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
)

func TransformProductGroupEntityToPb(ptr *sqlc.ProductGroup) *message.ProductGroup {
	return &message.ProductGroup{
		Id:           ptr.ID,
		BrandId:      ptr.BrandID,
		SortNo:       ptr.SortNo,
		Name:         ptr.Name,
		ProductCount: ptr.ProductCount,
	}
}

func MapProductGroupEntityToPb(list []*sqlc.ProductGroup, f func(*sqlc.ProductGroup) *message.ProductGroup) []*message.ProductGroup {
	r := make([]*message.ProductGroup, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transProductAttributeKeyValuesToPb(pak sqlc.ProductAttributeKey, valMap util.GroupObjectInt64Map) *message.ProductAttributeDef {
	return &message.ProductAttributeDef{
		Key: pak.Name,
		Values: util.MapToString(valMap[pak.ID], func(v interface{}) string {
			pav := v.(sqlc.ProductAttributeValue)
			return pav.Value
		}),
	}
}

func mapProductAttributeDefEntityToPb(keys []sqlc.ProductAttributeKey, valMap util.GroupObjectInt64Map, f func(sqlc.ProductAttributeKey, util.GroupObjectInt64Map) *message.ProductAttributeDef) []*message.ProductAttributeDef {
	r := make([]*message.ProductAttributeDef, len(keys))
	for i, item := range keys {
		r[i] = f(item, valMap)
	}
	return r
}

func transformProductSpecEntityToPb(productSpec sqlc.ProductSpec) *message.ProductSpec {
	return &message.ProductSpec{
		Id:                productSpec.ID,
		Name:              productSpec.Name,
		ProductAttributes: string(productSpec.ProductAttributes),
		Price:             productSpec.Price,
	}
}

func mapProductSpecEntityToPb(list []sqlc.ProductSpec, f func(sqlc.ProductSpec) *message.ProductSpec) []*message.ProductSpec {
	r := make([]*message.ProductSpec, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func TransformListNormalProductWithDistributeInfosByBrandIDRowToProductWithDistributeInfoPb(
	keys []sqlc.ProductAttributeKey,
	vals []sqlc.ProductAttributeValue,
	specs []sqlc.ProductSpec,
) func(*sqlc.ListNormalProductWithDistributeInfosByBrandIDRow) *message.ProductWithDistributeInfo {
	return func(ptr *sqlc.ListNormalProductWithDistributeInfosByBrandIDRow) *message.ProductWithDistributeInfo {
		var keysOfProduct []sqlc.ProductAttributeKey
		var specsOfProduct []sqlc.ProductSpec
		productID := ptr.ID
		for _, key := range keys {
			if key.ProductID == productID {
				keysOfProduct = append(keysOfProduct, key)
			}
		}
		for _, spec := range specs {
			if spec.ProductID == productID {
				specsOfProduct = append(specsOfProduct, spec)
			}
		}
		valMap := util.ListToInt64Map(util.Filter(util.ToGenericSlice(vals), func(i interface{}) bool {
			v := i.(sqlc.ProductAttributeValue)
			return v.ProductID == productID
		}), func(i interface{}) int64 {
			v := i.(sqlc.ProductAttributeValue)
			return v.ProductAttributeKeyID
		})

		return &message.ProductWithDistributeInfo{
			ProductId:            productID,
			Name:                 ptr.Name,
			Pics:                 ptr.Pics,
			HasSpecs:             ptr.HasSpecs,
			PriceMin:             ptr.PriceMin,
			PriceMax:             ptr.PriceMax,
			ProductGroupId:       ptr.ProductGroupID.Int64,
			ProductAttributeDefs: mapProductAttributeDefEntityToPb(keysOfProduct, valMap, transProductAttributeKeyValuesToPb),
			ProductSpecs:         mapProductSpecEntityToPb(specsOfProduct, transformProductSpecEntityToPb),
			PercentSale:          ptr.PercentSale,
			PercentOff:           ptr.PercentOff,
		}
	}
}

func MapListNormalProductWithDistributeInfosByBrandIDRowToProductWithDistributeInfoPb(list []*sqlc.ListNormalProductWithDistributeInfosByBrandIDRow, f func(*sqlc.ListNormalProductWithDistributeInfosByBrandIDRow) *message.ProductWithDistributeInfo) []*message.ProductWithDistributeInfo {
	r := make([]*message.ProductWithDistributeInfo, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func TransformListNormalProductWithDistributeInfosByBrandIDAndProductIDsRowToProductWithDistributeInfoPb(
	keys []sqlc.ProductAttributeKey,
	vals []sqlc.ProductAttributeValue,
	specs []sqlc.ProductSpec,
) func(*sqlc.ListNormalProductWithDistributeInfosByBrandIDAndProductIDsRow) *message.ProductWithDistributeInfo {
	return func(ptr *sqlc.ListNormalProductWithDistributeInfosByBrandIDAndProductIDsRow) *message.ProductWithDistributeInfo {
		var keysOfProduct []sqlc.ProductAttributeKey
		var specsOfProduct []sqlc.ProductSpec
		productID := ptr.ID
		for _, key := range keys {
			if key.ProductID == productID {
				keysOfProduct = append(keysOfProduct, key)
			}
		}
		for _, spec := range specs {
			if spec.ProductID == productID {
				specsOfProduct = append(specsOfProduct, spec)
			}
		}
		valMap := util.ListToInt64Map(util.Filter(util.ToGenericSlice(vals), func(i interface{}) bool {
			v := i.(sqlc.ProductAttributeValue)
			return v.ProductID == productID
		}), func(i interface{}) int64 {
			v := i.(sqlc.ProductAttributeValue)
			return v.ProductAttributeKeyID
		})

		return &message.ProductWithDistributeInfo{
			ProductId:            productID,
			Name:                 ptr.Name,
			Pics:                 ptr.Pics,
			HasSpecs:             ptr.HasSpecs,
			PriceMin:             ptr.PriceMin,
			PriceMax:             ptr.PriceMax,
			ProductGroupId:       ptr.ProductGroupID.Int64,
			ProductAttributeDefs: mapProductAttributeDefEntityToPb(keysOfProduct, valMap, transProductAttributeKeyValuesToPb),
			ProductSpecs:         mapProductSpecEntityToPb(specsOfProduct, transformProductSpecEntityToPb),
			PercentSale:          ptr.PercentSale,
			PercentOff:           ptr.PercentOff,
		}
	}
}

func MapListNormalProductWithDistributeInfosByBrandIDAndProductIDsRowToProductWithDistributeInfoPb(list []*sqlc.ListNormalProductWithDistributeInfosByBrandIDAndProductIDsRow, f func(*sqlc.ListNormalProductWithDistributeInfosByBrandIDAndProductIDsRow) *message.ProductWithDistributeInfo) []*message.ProductWithDistributeInfo {
	r := make([]*message.ProductWithDistributeInfo, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}
